iT邦幫忙

2026 iThome 鐵人賽

DAY 1
0
佛心分享-SideProject30

30 天走進 OpenClaw:一個 AI Agent 的誕生、掙扎與進化系列 第 1

第 1 天:我想跟一個 AI Agent 認識,先從 OpenClaw 開始

  • 分享至 

  • xImage
  •  

開場故事

如果今天你不是在跟一個聊天模型互動,而是在跟一個真的會做事、會排隊、會記得 session、還會把結果送回來的 AI Agent 互動,你第一個想知道的通常不是「它多會講」,而是:

  • 它怎麼開始做事?
  • 它怎麼知道現在輪到誰?
  • 它怎麼避免一邊做一邊把現場弄亂?

我寫這 30 天系列的起點,就是這三個問題。

OpenClaw 最吸引我的地方,不是它會回答,而是它很像一個真的有運作規則的系統。它不是把模型包成一個 API 就結束,而是把「接任務、排隊、執行、送達、留下紀錄」整套流程接起來。

所以第 1 天我不想只講設定或名詞。我想直接看 source code 怎麼把一個 run 接起來,怎麼建立 lane,怎麼做 admission,怎麼確認這個 session 現在真的可以開始工作。

如果只看設定,你會以為自己看懂了;但真正決定行為的,是 code 裡的接收、驗證、排隊和放行。

今天要解的問題

  • runEmbeddedAgent 怎麼把一次執行接起來?
  • sessionLaneglobalLane 是怎麼把工作排好?
  • beginSessionWorkAdmission 在擋什麼?
  • 為什麼這些邏輯不能只靠設定檔說明?
  • 第 1 天要先建立什麼樣的腦內模型,後面才不會迷路?

架構總覽

如果把 OpenClaw 拆成一句話,我會說:

它是一個把「對話」做成「有序工作流」的系統。

OpenClaw 不是看到訊息就直接丟模型,而是先進到 agent runtime,再依序處理:

  1. 接住 run
  2. 組裝 session / workspace / skills / prompt
  3. 排隊,避免同一個 session 同時亂跑
  4. 執行模型與工具
  5. 追蹤 lifecycle、stream、transcript
  6. 把結果送回去,必要時再延伸到 delivery

這也就是為什麼我覺得它比較像一個公司,而不是一個聊天玩具。

而且這一篇我不想只停在「它像什麼」,我想直接看它怎麼做。

原始碼節錄

先看 runtime 的入口。runEmbeddedAgent 不是直接開跑,它會先拿 config、建立 lifecycle,然後把工作交給內部流程。

export function runEmbeddedAgent(
  paramsInput: RunEmbeddedAgentParams,
): Promise<EmbeddedAgentRunResult> {
  const internalParamsInput = paramsInput as RunEmbeddedAgentInternalParams;
  const requestedProvider = normalizeOptionalString(internalParamsInput.provider);
  const requestedModel = normalizeOptionalString(internalParamsInput.model);
  const needsConfiguredDefault =
    !internalParamsInput.config && !requestedProvider && !requestedModel;
  const config =
    internalParamsInput.config ??
    (needsConfiguredDefault ? (getRuntimeConfigSnapshot() ?? undefined) : undefined);
  const lifecycleGeneration =
    internalParamsInput.lifecycleGeneration ??
    captureAgentRunLifecycleGeneration(internalParamsInput.runId);
  return withAgentRunLifecycleGeneration(lifecycleGeneration, () =>
    runEmbeddedAgentInternal({
      ...internalParamsInput,
      config,
      lifecycleGeneration,
    }),
  );
}

這段最重要的不是「它有一個 function」,而是它先做了三件事:

  • 決定這次 run 用哪個 config
  • 決定 lifecycle generation
  • 再交給真正執行的 runEmbeddedAgentInternal

也就是說,OpenClaw 不是先跑模型,而是先把這次跑步的規則框好。

接著看它怎麼把工作排進 session lane 與 global lane。

const sessionLane = resolveSessionLane(params.sessionKey?.trim() || params.sessionId);
const globalLane = resolveGlobalLane(params.lane);

這兩行看起來很短,但意思很重:

  • sessionLane 是同一個 session 的排隊線
  • globalLane 是更大的全域排隊線

如果同一個 session 正在跑,新的工作就不能隨便插隊;如果全域已經很忙,也要先照整體節奏走。

再往下看,真正進入工作前,還會做 session admission 與 session store 檢查:

const sessionWorkAdmission = await beginSessionWorkAdmission({
  scope: storePath ?? `agent:${sessionAgentId}`,
  identities: [sessionKey, sessionId],
  signal: opts.abortSignal,
  onInterrupt: () => lifecycleAbortController.abort(createAgentRunRestartAbortError()),
  assertAllowed: () => {
    const currentEntry =
      sessionStoreRuntime && storePath && sessionKey
        ? sessionStoreRuntime.loadSessionEntry({
            storePath,
            sessionKey,
            readConsistency: "latest",
          })
        : sessionEntry;
    if (!currentEntry && preparedSessionId) {
      throw new Error(`Session "${sessionKey ?? sessionId}" changed while starting work. Retry.`);
    }
    const matchesIntentionalRollover =
      isNewSession && currentEntry?.sessionId === preparedSessionId;
    if (
      currentEntry &&
      currentEntry.sessionId !== sessionId &&
      !matchesIntentionalRollover
    ) {
      throw new Error(`Session "${sessionKey ?? sessionId}" changed while starting work. Retry.`);
    }
    const archivedSessionError = resolveSessionWorkStartError(
      sessionKey ?? sessionId,
      currentEntry,
    );
    if (archivedSessionError) throw new Error(archivedSessionError);
    sessionEntry = currentEntry;
  },
});

這段的語氣很像在說:

「先確認這個 session 真的還是你要處理的那個 session,再開始做。」

這就是 OpenClaw 很核心的氣質:它不是急著跑,而是先保證沒有跑錯地方。

最後補一段真正的 admission controller。這邊可以更直接看出,OpenClaw 不是只靠設定,而是把設定轉成實際的 gate。

export async function beginSessionWorkAdmission(params: {
  scope: string;
  identities: Iterable<string | undefined>;
  assertAllowed: () => Promise<void> | void;
  revalidateAllowed?: () => Promise<void> | void;
  onInterrupt?: () => void;
  signal?: AbortSignal;
}): Promise<SessionWorkAdmissionLease> {
  if (isGatewaySubordinateWorkAdmissionClosed()) {
    throw new GatewayDrainingError();
  }
  const identities = normalizeSessionIdentities(params.scope, params.identities);
  return await runExclusiveSessionLifecycle({
    scope: params.scope,
    identities: params.identities,
    signal: params.signal,
    run: async () => {
      await params.assertAllowed();
      if (isGatewaySubordinateWorkAdmissionClosed()) {
        throw new GatewayDrainingError();
      }
      ...
    },
  });
}

這段在做的事很像門禁:

  • 先看系統有沒有關門
  • 再把 session identity 正規化
  • 然後進入 exclusive lifecycle
  • assertAllowed,通過了才真的放行

也就是說,設定不是答案,設定只是原料;真正的規則,是 code 把它變成了 gate。

白話拆解

我很喜歡把這一層想成一支在比賽的隊伍。

1. runEmbeddedAgent 像賽事報名

你不能一進場就衝。
你要先知道:

  • 你是誰
  • 這次用哪個配置
  • 這次是不是同一場比賽

runEmbeddedAgent 做的就是這件事。它不是模型本體,而是把賽事規則先定好。

2. queue 像現場秩序

如果同一個 session 同時兩個 turn 一起跑,結果通常很慘。

OpenClaw 用 lane 來保證:

  • 同 session 的 run 會排隊
  • 全域也有額外的節流與佇列
  • 進入工作前會先看有沒有被卡住或中斷

這很像工地現場先分區,再讓機具進場,不是所有人一起往裡衝。

3. session admission 像門禁

beginSessionWorkAdmission 這段很重要。

它在做的不是「把事情啟動」,而是「確認這次啟動沒有衝突」。

如果 session 已經變了、已經被封存了、或者不是你現在該接的那個,系統會直接擋下來。

這就是為什麼 OpenClaw 很像一個正式制度,而不是臨時湊出來的腳本。

4. lifecycle 像行車紀錄器

captureAgentRunLifecycleGenerationwithAgentRunLifecycleGeneration 這種東西,像是在幫每一次 run 打上世代號碼。

這樣做的好處是:

  • 你知道這次 run 屬於哪個生命週期
  • 如果中途重啟或切換,系統知道哪個事件還有效
  • 程序不會把過期資料誤當成最新狀態

這就像行車紀錄器,出事時才知道是哪一段流程在動。

設計取捨

好處

  • 同一個 session 不會亂打架
  • lifecycle 清楚,重啟與中斷比較可控
  • 工作流有秩序,不是單純一次性呼叫模型
  • 後續的 session store、delivery、tool call 都能接在同一套規則上

代價

  • 第一眼看起來很厚
  • 要理解 run、lane、session、lifecycle 的關係
  • 除錯不是看一個 function 就能解

但這個代價值得。

因為 AI Agent 真正難的地方,從來不是「叫模型說話」,而是「讓它穩定地做事」。

今天的結論

  • OpenClaw 的核心不是單次呼叫,而是 agent loop
  • runEmbeddedAgent 先建立 config 與 lifecycle,再進入實作
  • session lane 與 global lane 讓同一個系統不會互相踩踏
  • beginSessionWorkAdmission 把設定轉成真的 gate
  • 第 1 天最值得記住的,不是所有細節,而是「OpenClaw 是一個有秩序的執行系統」

下一步

第 1 天先不要急著把每個函式背起來。

先記住一件事就夠了:

OpenClaw 不是先回答,而是先排隊、先確認、再執行。

第 2 天我會接著看,這個秩序到底是怎麼被拆成幾層架構的。


系列文
30 天走進 OpenClaw:一個 AI Agent 的誕生、掙扎與進化1
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言